﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using AwesomeGame.Map;
using AwesomeGame.Weapons;

namespace AwesomeGame
{
    public class Tank
    {
        public delegate void TankEvent(Vector2 position, float rotation, Tank sender);
        public event TankEvent TankMoved;
        public event TankEvent TankFired;
        public event TankEvent DroppedBomb;

        public TimeSpan LastTeleport = new TimeSpan(0, -1, 0);
        public Vector2 Position;
        private Dictionary<TankAnimations, List<Texture2D>> _animations = new Dictionary<TankAnimations, List<Texture2D>>();
        private TankAnimations _currentAnimation = TankAnimations.Waiting;
        private bool _acceptingUserInput;
        private float _movementSpeed;
        public float Rotation = 0f;
        private Vector2 _spriteMidpoint;
        private int _currentFrame = 0;
        private TimeSpan _lastAnimationUpdate = new TimeSpan();
        private TimeSpan _lastBombDropped = new TimeSpan(0, -1, 0);
        private Level _level;
        public WeaponType Weapon = WeaponType.Bullet;
        private double _turbo = 25;
        private float _turboSpeed;
        private int _turboPause = 0;
        private double _turboPauseTime = 5;
        private double TURBOCONSTANTTIME = 200;
        public int _tankIsSafe = 0;

        public long Id;

        public Tank(Vector2 position, bool controllable, ref Level level)
        {
            _level = level;
            Position = position;
            SetAnimations();
            _acceptingUserInput = controllable;
            _movementSpeed = 2f;
            _turboSpeed = 5f;
            _spriteMidpoint.X = _animations[TankAnimations.Waiting][0].Width / 2;
            _spriteMidpoint.Y = _animations[TankAnimations.Waiting][0].Height / 2;
        }

        public Rectangle GetCollisionRectangle()
        {
            return new Rectangle((int)(Position.X - _spriteMidpoint.X), (int)(Position.Y - _spriteMidpoint.Y), 50, 50);
        }

        public Rectangle GetCollisionRectangle(Vector2 position)
        {
            return new Rectangle((int)(position.X - _spriteMidpoint.X), (int)(position.Y - _spriteMidpoint.Y), 50, 50);
        }

        public bool PointIntersectsWithTank(Vector2 point)
        {
            if ((point.X >= Position.X - _spriteMidpoint.X) && (point.X <= Position.X + _spriteMidpoint.X) && (point.Y >= Position.Y - _spriteMidpoint.Y) && (point.Y <= Position.Y + _spriteMidpoint.Y))
                return true;
            return false;
        }

        private void SetAnimations()
        {
            List<Texture2D> animation = new List<Texture2D>();
            animation.Add(Game1.ContentManager.Load<Texture2D>(@"Tank"));

            _animations.Add(TankAnimations.Waiting, animation);

            List<Texture2D> firingAnimation = new List<Texture2D>();
            firingAnimation.Add(Game1.ContentManager.Load<Texture2D>(@"Tank-Fire1"));
            firingAnimation.Add(Game1.ContentManager.Load<Texture2D>(@"Tank-Fire2"));
            firingAnimation.Add(Game1.ContentManager.Load<Texture2D>(@"Tank-Fire3"));
            firingAnimation.Add(Game1.ContentManager.Load<Texture2D>(@"Tank-Fire4"));
            _animations.Add(TankAnimations.Firing, firingAnimation);

            List<Texture2D> safetyAnimation = new List<Texture2D>();
            safetyAnimation.Add(Game1.ContentManager.Load<Texture2D>(@"Tank"));
            safetyAnimation.Add(Game1.ContentManager.Load<Texture2D>(@"TankSafe"));
            _animations.Add(TankAnimations.Safety, safetyAnimation);
        }

        public void Fire()
        {
            if (_currentAnimation != TankAnimations.Firing)
            {
                _currentFrame = 0;
                _currentAnimation = TankAnimations.Firing;
                if (TankFired != null)
                    TankFired(Position, Rotation, this);
            }
        }

        public void DropBomb(GameTime gameTime)
        {
            if (gameTime.TotalGameTime - _lastBombDropped >= new TimeSpan(0, 0, 10))
            {
                if (DroppedBomb != null)
                    DroppedBomb(Position, Rotation, this);

                _lastBombDropped = gameTime.TotalGameTime;
            }
        }

        private void AdvanceAnimationFrame()
        {
            if (_currentFrame + 1 < _animations[_currentAnimation].Count)
                _currentFrame += 1;
            else
            {
                _currentFrame = 0;
                _currentAnimation = TankAnimations.Waiting;
            }
        }

        public void Update(GameTime gameTime)
        {
            if (gameTime.TotalGameTime - _lastAnimationUpdate >= new TimeSpan(0, 0, 0, 0, 100))
            {
                AdvanceAnimationFrame();
                _lastAnimationUpdate = gameTime.TotalGameTime;
            }
            if (_acceptingUserInput)
            {
                KeyboardState state = Keyboard.GetState();
                Vector2 previousPosition = new Vector2(Position.X, Position.Y);
                float previousRotation = Rotation;

                if (state.IsKeyDown(Keys.Left))
                    Rotation -= 0.05f;
                if (state.IsKeyDown(Keys.Right))
                    Rotation += 0.05f;
                if (state.IsKeyDown(Keys.Up))
                    MoveForward();
                if (state.IsKeyDown(Keys.Down))
                    MoveBackwards();
                if (state.IsKeyDown(Keys.Z))
                    Fire();
                if (state.IsKeyDown(Keys.X))
                    DropBomb(gameTime);

                if (Position.X != previousPosition.X || Position.Y != previousPosition.Y || Rotation != previousRotation)
                    if (TankMoved != null)
                        TankMoved(Position, Rotation, this);
            }
            if (_turboPause == 1)
            {
                _turboPauseTime -= 1;
                if (_turboPauseTime <= 0)
                {
                    _turboPause = 0;
                    _turboPauseTime = TURBOCONSTANTTIME;
                }
            }
            if (_turbo < 10)
            {
                _turbo += 0.2;
            }
            if (_tankIsSafe > 0)
            {
                _tankIsSafe -= 1;
                if (_currentAnimation == TankAnimations.Waiting)
                {
                    _currentAnimation = TankAnimations.Safety;
                }
            }
        }

        public void MoveForward()
        {
            KeyboardState state = Keyboard.GetState();
            if (_turbo <= 0.1)
            {
                _turboPause = 1;
            }
            if ((state.IsKeyDown(Keys.LeftShift)) && (_turbo > 0))
            {
                if (_turboPause == 0)
                {
                    _turbo -= 1;
                    Vector2 newPosition = new Vector2((float)(Position.X + Math.Cos(Rotation) * _turboSpeed), (float)(Position.Y + Math.Sin(Rotation) * _turboSpeed));
                    if (CanMoveToPosition(newPosition))
                        Position = newPosition;
                }
                else
                {
                    Vector2 newPosition = new Vector2((float)(Position.X + Math.Cos(Rotation) * _movementSpeed), (float)(Position.Y + Math.Sin(Rotation) * _movementSpeed));
                    if (CanMoveToPosition(newPosition))
                        Position = newPosition;
                }
            }
            else
            {
                Vector2 newPosition = new Vector2((float)(Position.X + Math.Cos(Rotation) * _movementSpeed), (float)(Position.Y + Math.Sin(Rotation) * _movementSpeed));
                if (CanMoveToPosition(newPosition))
                    Position = newPosition;
            }
        }

        public void MoveBackwards()
        {
            Vector2 newPosition = new Vector2((float)(Position.X - Math.Cos(Rotation) * _movementSpeed), (float)(Position.Y - Math.Sin(Rotation) * _movementSpeed));
            if (CanMoveToPosition(newPosition))
                Position = newPosition;
        }

        private bool CanMoveToPosition(Vector2 worldPosition)
        {
            Rectangle collisionRectangle = GetCollisionRectangle(worldPosition);
            List<Vector2> points = new List<Vector2>();
            points.Add(new Vector2(collisionRectangle.X, collisionRectangle.Y));
            points.Add(new Vector2(collisionRectangle.X, collisionRectangle.Y + collisionRectangle.Height));
            points.Add(new Vector2(collisionRectangle.X + collisionRectangle.Width, collisionRectangle.Y));
            points.Add(new Vector2(collisionRectangle.X + collisionRectangle.Width, collisionRectangle.Y + collisionRectangle.Height));

            foreach (Vector2 point in points)
            {
                TileTypes tile = _level.GetTileAtWorldPosition(point);
                if (tile == TileTypes.Wall)
                    return false;
                DestructableWorldItem item = _level.GetDestructableItemAtWorldPosition(point);
                if (item != null)
                    if (item.isDestroyed == false)
                        return false;
            }            

            return true;
        }

        public void Draw(GameTime gameTime)
        {
            Vector2 screenPosition = Camera.GetScreenPosition(Position);
            Texture2D currentFrame = _animations[_currentAnimation][_currentFrame];
            Game1.SpriteBatch.Draw(currentFrame, screenPosition, null, Color.White, Rotation, _spriteMidpoint, 1f, SpriteEffects.None, 0.7f);
        }
    }

    public enum TankAnimations
    {
        Waiting = 0,
        Firing = 1,
        Safety
    }
}